#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

// ./a.out 172.16.101.26 debug.txt

int main(int argc, char const *argv[])
{
    if(argc != 3) {
        printf("./a.out server_ip  fileName\n");
        return 0;
    }

    //创建udp套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    //构建下载报文
    unsigned char cmd[512]="";
    //需求：以文本模式下载a.txt
    int len = sprintf(cmd, "%c%c%s%c%s%c", 0, 1, argv[2], 0, "octet", 0);
    //将cmd发送至  服务器的69号端口
    struct sockaddr_in ser_addr;
    bzero(&ser_addr, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(69);
    ser_addr.sin_addr.s_addr = inet_addr(argv[1]);
    //inet_pton(AF_INET, "10.9.21.211", &ser_addr.sin_addr.s_addr);
    sendto(sockfd, cmd, len,0,\
    (struct sockaddr *)&ser_addr, sizeof(ser_addr));

    //打开文件文件 写的方式
    int fd = open(argv[2], O_WRONLY|O_CREAT, 0666);
    if(fd<0) {
        perror("open");
        return 0;
    }

    //定义要接收的包编号
    int pack_num=0;

    //接收服务器的应答数据
    while(1){
        struct sockaddr_in from_addr;
        socklen_t from_len = sizeof(from_addr);
        unsigned char buf[1500]="";
        int len = recvfrom(sockfd, buf,sizeof(buf), 0,\
        (struct sockaddr *)&from_addr, &from_len);

        //判断当前buf中的报文功能
        if(buf[1] == 5) {
            printf("err");
            break;
        } else if(buf[1] == 3) {
            //文件数据
            if((pack_num+1) == ntohs(*(unsigned short *)(buf+2))) {
                pack_num = ntohs(*(unsigned short *)(buf+2));
                printf("pack_num=%d\n", pack_num);
                //将文件数据写入本地磁盘文件
                write(fd, buf+4, len-4);
            }
            //回应ACK
            buf[1]=4;
            sendto(sockfd, buf,4,0,\
            (struct sockaddr *)&from_addr, sizeof(from_addr));

            //如果len<516接收文件完毕 退出
            if(len < 516) {
                break;
            }
        }
    }

    //关闭文件
    close(fd);
    //关闭套接字
    close(sockfd);

    return 0;
}